<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>自定义事件</title>
		<script src="../vue.js"></script>
	</head>
	<body>
		<!-- 1 事件名
		 不同于组件和 prop，事件名不会被用作一个 JavaScript 变量名或 property 名，
		 所以就没有理由使用 camelCase 或 PascalCase 了。
		 并且 v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的)，
		 所以 v-on:myEvent 将会变成 v-on:myevent——导致 myEvent 不可能被监听到。
		 因此，我们推荐你始终使用 kebab-case 的事件名。
		 -->
		
		<!-- 2 自定义组件的 v-model -->
		<div id="app1">
			<label for="c1">cmt1</label>
			<cmt1 id="c1" :checked="checked"></cmt1>
		</div>
		<hr />
		<!-- 3 将原生事件绑定到组件 -->
		<!--   3.1 不使用 .native -->
    <div id="app2">
			<label for="c2">cmt2</label>
			<cmt2 id="c2" @focus="onFocus"></cmt2>
		</div>
		<hr />
    <!--   3.2 使用 .native。你可能有很多次想要在一个组件的根元素上直接监听一个原生事件。这时，你可以使用 v-on 的 .native 修饰符： -->
    <div id="app2-2">
    	<label for="c2-2">cmt2-2</label>
    	<cmt2-2 id="c2-2" @focus.native="onFocus"></cmt2-2>
    </div>
    <hr />
    <!--   3.3 不能使用 .native 的情况。在有的时候这是很有用的，不过在你尝试监听一个类似 <input> 的非常特定的元素时，
    这并不是个好主意。比如上述 <base-input> 组件可能做了如下重构，所以根元素实际上是一个 <label> 元素： -->
    <div id="app3">
    	<label for="c3">cmt3</label>
    	<cmt3 id="c3" label="label3" @focus.native="onFocus"></cmt3>
    </div>
		<hr />
    <!--   3.4 不能使用 .native 的情况下，可以使用 $listeners property -->
    <div id="app4">
    	<label for="c4">cmt4</label>
    	<cmt4 id="c4" v-model="value" @focus="onFocus" label="label4"></cmt4>
      {{value}}
    </div>
    <hr />
		<!-- 4 .sync 修饰符   ??? 不是很理解 -->
    <div id="app5">
      <label for="c5">cmt5</label>
      <cmt5 id="c5" v-bind:title.sync="title1" v-bind:new-title="title1"
      ></cmt5>
    </div>
    <hr />
		<script type="text/javascript">
		// 1 事件名
		// 2 自定义组件的 v-model
		Vue.component('cmt1', {
			model: {
				prop: 'checked',
				event: 'change'
			},
			props: {
				checked: Boolean
			},
			template: `
			  <input type="checkbox" 
			    :checked="checked"
				v-on:change="$emit('change', $event.target.checked)"
			  >
			`
		})
		
		var vm1 = new Vue({
			el: '#app1',
			data: {
				checked: true
			}
		})
		
		// 3 将原生事件绑定到组件
    /* 背景知识：Vue自定义事件和原生事件
          自定义事件：子组件在父组件中使用时，直接绑定在子组件上的事件就是自定义事件，必须经过子组件的触发才能执行
          原生事件：直接在子组件里的模板上绑定的事件，子组件引入后是可以直接使用的
          参考链接：https://blog.csdn.net/weixin_42129241/article/details/114327025
    */
    //   3.1 不使用 .native，则需要在子组件中手动触发
    Vue.component('cmt2', {
      props: ['value'],
    	template: `
        <input 
          v-bind="$attrs"
          :value="value"
          @focus="$emit('focus')"
        >
    	`
    })
    new Vue({
    	el: '#app2',
      methods: {
        onFocus: function() {
          // alert('vue instance2 - onFocus event')
          document.getElementById('c2').value='vue2-onFocus event'
        }
      }
    })
    //   3.2 使用 .native，则不需子组件触发
		Vue.component('cmt2-2', {
      props: ['value'],
			template: `
        <input 
          v-bind="$attrs"
          :value="value"
        >
			`
		})
    new Vue({
    	el: '#app2-2',
      methods: {
        onFocus: function() {
          // alert('vue instance2-2 - onFocus event')
          document.getElementById('c2-2').value='vue2-2-onFocus event'
        }
      }
    })
		
    //   3.3 不能使用 .native 的情况
    Vue.component('cmt3', {
      props: ['label', 'value'],
    	template: `
        <label>
          {{label}}
          <input 
            v-bind="$attrs"
            :value="value"
            v-on:input="$emit('input', $event.target.value)"
          >
        </label>
    	`
    })
		
    new Vue({
    	el: '#app3',
      methods: {
        onFocus: function() {
          // alert('vue instance3 - onFocus event')
          document.getElementById('c3').value='vue3-onFocus event'
        }
      }
    })
    //   3.4 不能使用 .native 的情况下，可以使用 $listeners property
    //        以下例子绑定了 input和 focus 事件
    Vue.component('cmt4', {
      inheritAttrs: false,
      props: ['label', 'value'],
      computed: {
        inputListeners: function() {
          var vm = this
          // `Object.assign` 将所有的对象合并为一个新对象
          return Object.assign({}, 
            // 我们从父级添加所有的监听器
            this.$listeners,
            // 然后我们添加自定义监听器，或覆写一些监听器的行为
            {
              // 这里确保组件配合 `v-model` 的工作
              input: function(event) {
                vm.$emit('input', event.target.value)
              },
              focus: function(event) {
                vm.$emit('focus')
              }
            }
          )
        }
      },
      template: `
        <label>
          {{label}}
          <input v-bind="$attrs"
            v-bind:value="value"
            v-on="inputListeners"
          >
        </label>
      `
    })
    
    new Vue({
    	el: '#app4',
      data: {
        value: 'value4'
      },
      methods: {
        onFocus: function() {
          // alert('vue instance4 - onFocus event')
          document.getElementById('c4').value='vue4-onFocus event'
        }
      }
    })
    
		// 4 .sync 修饰符 ??? 不是很理解
		Vue.component('cmt5', {
      props: ['title', 'newTitle'],
      template: `
        <input
          v-bind="$attrs"
          :value="newTitle"
          v-on:update:title="$emit('update:title', newTitle)"
        >
      `
    })
    
    var vm5 = new Vue({
      el: '#app5',
      data: {
        title1: 'title1',
        newTitle1: 'newTitle1'
      }
    })
    
		</script>
	</body>
</html>
